home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / accounts / npasswd_.000 / npasswd_ / npasswd_boulder / pw_passwd.c < prev    next >
C/C++ Source or Header  |  1995-04-06  |  10KB  |  406 lines

  1.  
  2. /* --------------------------------------------------------------------  */
  3. /*                                                                       */
  4. /*                         Author: Clyde Hoover                          */
  5. /*                          Computation Center                           */
  6. /*                   The University of Texas at Austin                   */
  7. /*                          Austin, Texas 78712                          */
  8. /*                         clyde@emx.utexas.edu                          */
  9. /*                   uunet!cs.utexas.edu!ut-emx!clyde                    */
  10. /*                                                                       */
  11. /*This code may be distributed freely, provided this notice is retained. */
  12. /*                                                                       */
  13. /* --------------------------------------------------------------------  */
  14. /*
  15.  *    pw_passwd - Routines for dealing with password files.
  16.  *        Handles V7 / *.* BSD / Sys V format.
  17.  */
  18. #include <stdio.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <signal.h>
  22. #include <errno.h>
  23. #include <pwd.h>
  24. #include <fcntl.h>
  25.  
  26. #ifndef lint
  27. static char sccsid[] = "@(#)pw_passwd.c    1.9 1/24/91 (cc.utexas.edu)";
  28. #endif
  29.  
  30. #define    SLOP    128    /*  Size difference tolerated old <> new passwd file */
  31.  
  32. #ifdef    SYSV
  33. /*
  34.  *    System V password aging stuff
  35.  */
  36. #define    SEC_PER_WEEK    ((long )24 * 7 * 60 * 60)
  37.  
  38. extern long a64l();
  39. extern char *l64a();
  40.  
  41. static time_t    pwage = 0,
  42.         maxpwtime = 0,
  43.         minpwtime = 0,
  44.         now;
  45. #endif
  46.  
  47. typedef struct passwd    passwd;
  48. typedef    struct passwd    *passwdp;
  49.  
  50. static passwd    theUser,        /* The user to change */
  51.         Me;            /* The user who invoked command */
  52. static int    myuid,            /* Uid of program */
  53.         mytempfile = 0;        /* Does PASSWD_TEMP belong to me? */
  54.  
  55. /*
  56.  *    File names
  57.  */
  58. #ifndef    PASSWD_FILE
  59. #define    PASSWD_FILE    "/etc/passwd"
  60. #endif
  61.  
  62. #ifndef    PASSWD_SAVE
  63. #define    PASSWD_SAVE    "/etc/opasswd"
  64. #endif
  65.  
  66. #ifndef    PASSWD_TEMP
  67. #define    PASSWD_TEMP    "/etc/ptmp"
  68. #endif
  69.  
  70. #define    PASSWD_MODE    0644
  71.  
  72. #ifdef    DEBUG
  73. static char    *passwdtemp = "./etc_ptmp",
  74.         *passwdfile = "./etc_passwd",
  75.         *savefile = "./etc_opasswd";
  76. #else
  77. static char    *passwdtemp = PASSWD_TEMP,
  78.         *passwdfile = PASSWD_FILE,
  79.         *savefile = PASSWD_SAVE;
  80. #endif
  81.  
  82. extern int    errno;
  83.  
  84. char    *getlogin(),
  85.     *crypt();
  86.  
  87. /*
  88.  *    pw_initialize - set up
  89.  */
  90. pw_initialize()
  91. {
  92.     passwdp    me;    /* Temp */
  93.     char    *myname = getlogin();    /* Name of invoker */
  94.  
  95. #ifdef    DEBUG
  96.     setpwfile(passwdfile);
  97. #endif
  98.     myuid = getuid();
  99.     if (myname && *myname) {
  100.         if ((me = getpwnam(myname)) == NULL)
  101.             quit(1, "Cannot get user identification from name.\n");
  102.     } else {
  103.         if ((me = getpwuid(myuid)) == NULL)
  104.             quit(1, "Cannot get user identification from uid.\n");
  105.     }
  106.  
  107.     _cppasswd(me, &Me);
  108.     return(1);
  109. }
  110.  
  111. /*
  112.  *    pw_getuserbyname - get password 
  113.  *
  114.  *    Returns 1 if passwd info found for <name>
  115.  *        0 otherwise
  116.  */
  117. pw_getuserbyname(name, passwdb)
  118. char    *name,        /* User name */
  119.     *passwdb;    /* Where to stuff password */
  120. {
  121.     passwdp    p;    /* Temp */
  122.  
  123.     if ((p = getpwnam(name)) == NULL)
  124.         return(0);
  125.     _cppasswd(p, &theUser);
  126.     (void) strcpy(passwdb, p->pw_passwd);
  127.     return(1);
  128. }
  129.  
  130. /*
  131.  *    pw_permission - check password change permission
  132.  *
  133.  *    Returns 1 if password can be changed
  134.  *        0 if not
  135.  */
  136. pw_permission()
  137. {
  138.     if (strcmp(Me.pw_name, theUser.pw_name) && myuid)
  139.         return(0);
  140.  
  141.     /*
  142.      * Other checks can be put here to determine if the invoker should
  143.      * be allowed to change this password.
  144.      */
  145. #ifdef HAS_PW_AGE
  146.     if (theUser.pw_age) {
  147.         pwage = a64l(theUser.pw_age);
  148.         maxpwtime = pwage & 077;
  149.         minpwtime = (pwage >> 6) & 077;
  150.         pwage >>= 12;
  151.         (void) time(&now);
  152.         now /= SEC_PER_WEEK;
  153.         if (pwage <= now) {
  154.             if (myuid && (now < (pwage + minpwtime))) {
  155.                 fprintf(stderr, 
  156.                      "Sorry: < %ld  weeks since last change\n",
  157.                      minpwtime);
  158.                 return(0);
  159.             }
  160.             if ((minpwtime > maxpwtime) && myuid) {
  161.                 fprintf(stderr,
  162.                     "You may not change this password.\n");
  163.                 return(0);
  164.             }
  165.         }
  166.     }
  167. #endif
  168.     return(1);
  169. }
  170.  
  171. /*
  172.  *    pw_compare - compare old and new passwords
  173.  *
  174.  *    Returns 1 if check = new, 0 if not
  175.  */
  176. pw_compare(current, check)
  177. char    *current,        /* Current pw (encrypted) */
  178.     *check;            /* check pw (plain) */
  179. {
  180.     if (!*current)
  181.         return(0);
  182.     return(!strcmp(current, crypt(check, current)));
  183. }
  184.  
  185. /*
  186.  *    pw_check - sanity check password.  Right now just calls
  187.  *        the password check program
  188.  *
  189.  *    Returns 1 if password is ok to use, 0 otherwise
  190.  */
  191. pw_check(newpw)
  192. char    *newpw;        /* New password (plain) */
  193. {
  194.     /* Put other administrative checks here */
  195.     return(checkpasswd(theUser.pw_uid, newpw));
  196. }
  197.  
  198. /*
  199.  *    pw_replace - replace password in passwd file 
  200.  */
  201. pw_replace(newpwd, curpwd)
  202. char    *newpwd,        /* New password (plain) */
  203.     *curpwd;        /* Old password (plain) */
  204. {
  205. #ifdef    SYSV
  206.     int    (*sigint)(),        /* Save SIGINT */
  207.         (*sigquit)();        /* Save SIGQUIT */
  208. #else
  209.     long    oldsigs,        /* Signal mask save */
  210.         blocksigs = sigmask(SIGINT) |    /* Signals to block */
  211.                 sigmask(SIGQUIT) |    /* while updating */
  212.                 sigmask(SIGTSTP);    /* password file */
  213. #endif
  214.     passwdp px;        /* Temp */
  215.     char    salt[4];    /* Encryption salt */
  216.     FILE    *tf;        /* File ptr to new passwd file */
  217.     int    fd;        /* File desc. to new passwd file */
  218.     struct stat    oldstat,    /* Stat of current passwd file */
  219.             newstat;    /* Stat of new passwd file */
  220.  
  221.     /*
  222.      * Prepare password entry 'theUser' for replacement
  223.      */
  224.     randomstring(salt, sizeof(salt));
  225.     theUser.pw_passwd = crypt(newpwd, salt);
  226. #ifdef HAS_PW_AGE
  227.     /*
  228.      * Update password age field
  229.      */
  230.     if (theUser.pw_age) {
  231.         if (maxpwtime == 0)
  232.             *theUser.pw_age = '\0';
  233.         else {
  234.             now = time((time_t *)0) / SEC_PER_WEEK;
  235.             pwage = maxpwtime
  236.                 + (minpwtime << 6)
  237.                 + (now << 12);
  238.             theUser.pw_age = l64a(pwage);
  239.         }
  240.     }
  241. #endif
  242.     (void) umask(0);
  243.     (void) stat(passwdfile, &oldstat);
  244.     fd = open(passwdtemp, O_WRONLY|O_CREAT|O_EXCL, PASSWD_MODE);
  245.     if (fd < 0) {
  246.         if (errno == EEXIST)
  247.             quit(0, "Password file busy - try again.\n");
  248.         perror("Tempfile create");
  249.         quit(1, "Cannot create temp file.\n");
  250.     }
  251.     mytempfile = 1;
  252.     if ((tf = fdopen(fd, "w")) == NULL)
  253.         quit(1, "Cannot fdopen temp file.");
  254. #ifdef    SYSV
  255.     sigint = signal(SIGINT, SIG_IGN);
  256.     sigquit = signal(SIGQUIT, SIG_IGN);
  257. #else
  258.     oldsigs = sigblock(blocksigs);
  259. #endif
  260.     setpwent();
  261.     while ((px = getpwent()) != NULL) {
  262.         if (px->pw_name == 0 || px->pw_name[0] == 0) /* Sanity check */
  263.             continue;
  264.         if (strcmp(px->pw_name, theUser.pw_name) == 0)
  265.             px = &theUser;
  266.         (void) putpwent(px, tf);
  267.     }
  268.     endpwent();
  269.     (void) fflush(tf);
  270.     (void) fstat(fileno(tf), &newstat);
  271.     (void) fclose(tf);
  272.     /*
  273.      * Check if the new password file is complete.  Since the encrypted
  274.      * password is of a fixed length, the new file should be roughly
  275.      * the same size as the old one.
  276.      */
  277.     if (newstat.st_size < (oldstat.st_size - SLOP))
  278.         quit(1, "New password file appears to be incomplete - aborting.\n");
  279.  
  280.     if (rename(passwdfile, savefile) < 0) {
  281.         perror("Password file save");
  282.         unlink(passwdtemp);
  283.         quit(1, "Can't save password file");
  284.     }
  285.     if (rename(passwdtemp, passwdfile) < 0) {
  286.         perror("Password file replace");
  287.         (void) unlink(passwdtemp);
  288.         (void) link(savefile, passwdfile);
  289.         quit(1, "Can't replace password file");
  290.     }
  291. #ifdef NO_PASSWD_SAVE
  292.     (void) unlink(savefile);
  293. #endif
  294. #ifdef    BSD4_3
  295.     updatedbm();
  296. #endif
  297. #ifdef    SYSV
  298.     (void) signal(SIGINT, sigint);
  299.     (void) signal(SIGQUIT, sigquit);
  300. #else
  301.     (void) sigsetmask(oldsigs);
  302. #endif
  303. }
  304.  
  305. /*
  306.  *    pw_cleanup - clean up after myself
  307.  */
  308. pw_cleanup(code)
  309. int    code;        /* 0 for normal, 1 for abort */ /*NOTUSED*/
  310. {
  311.     if (mytempfile)
  312.         (void) unlink(passwdtemp);
  313. }
  314.  
  315. /*
  316.  *    _newstr - copy string into new storage
  317.  */
  318. static char *
  319. _newstr(s)
  320. char    *s;        /* String to copy */
  321. {
  322.     register char    *t;    /* Temp */
  323.     char    *malloc();
  324.  
  325.     if (s == NULL)
  326.         return(0);
  327.     t = malloc(strlen(s) + 1);
  328.     if (t == NULL)
  329.         quit(1, "No memory.\n");
  330.     (void) strcpy(t, s);
  331.     return(t);
  332. }
  333.  
  334. /*
  335.  *    _cppasswd - copy a passwd structure
  336.  */
  337. static
  338. _cppasswd(f,t)
  339. passwdp    f,        /* From */
  340.     t;        /* To */
  341. {
  342.     *t = *f;
  343.     t->pw_name = _newstr(f->pw_name);
  344. #ifdef HAS_PW_AGE
  345.     t->pw_age = _newstr(f->pw_age);
  346. #endif
  347.     t->pw_passwd = _newstr(f->pw_passwd);
  348. #ifdef HAS_PW_COMMENT
  349.     t->pw_comment = _newstr(f->pw_comment);
  350. #endif
  351.     t->pw_gecos = _newstr(f->pw_gecos);
  352.     t->pw_dir = _newstr(f->pw_dir);
  353.     t->pw_shell = _newstr(f->pw_shell);
  354. }
  355.  
  356. #ifdef    BSD4_3
  357. /*
  358.  *    Update the hashed password data base
  359.  */
  360. #include <ndbm.h>
  361.  
  362. #define    SCOPY(S) xp = (S); while (*cp++ = *xp++)
  363. #define    BCOPY(B) bcopy((char *)&(B), cp, sizeof(int)); cp += sizeof(int)
  364.  
  365. updatedbm()
  366. {
  367.     DBM    *pwd;        /* DBM data base passwd */
  368.     register char    *cp,    /* Data storage pointer */
  369.             *xp;    /* String copy pointer */
  370.     datum    key,        /* DBM key datum */
  371.         data;        /* DBM data store datum */
  372.     char    buf[512];    /* Data buffer */
  373.  
  374.     pwd = dbm_open(passwdfile, O_RDWR, 0);
  375.     if (pwd == 0)
  376.         return;
  377.     cp = buf;
  378.     /* Pack passwd entry in the form expected by the getpw* routines */
  379.     SCOPY(theUser.pw_name);
  380.     SCOPY(theUser.pw_passwd);
  381.     BCOPY(theUser.pw_uid);
  382.     BCOPY(theUser.pw_gid);
  383.     BCOPY(theUser.pw_quota);
  384.     SCOPY(theUser.pw_comment);
  385.     SCOPY(theUser.pw_gecos);
  386.     SCOPY(theUser.pw_dir);
  387.     SCOPY(theUser.pw_shell);
  388.  
  389.     data.dptr = buf;
  390.     data.dsize = cp - buf;
  391.     key.dptr = theUser.pw_name;
  392.     key.dsize = strlen(theUser.pw_name);
  393.     if (dbm_store(pwd, key, data, DBM_REPLACE) < 0) {
  394.         perror("dbm_store (name)");
  395.         quit(1, "Can't store passwd entry (name key).\n");
  396.     }
  397.     key.dptr = (char *)&theUser.pw_uid;
  398.     key.dsize = sizeof (int);
  399.     if (dbm_store(pwd, key, data, DBM_REPLACE) < 0) {
  400.         perror("dbm_store (uid)");
  401.         quit(1, "Can't store passwd entry (uid key).\n");
  402.     }
  403.     dbm_close(pwd);
  404. }
  405. #endif
  406.